package cn.ray_land.flashairtest;

import android.os.Handler;
import android.os.Looper;
import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Calendar;
import java.util.UUID;

public class FlashAirUploader {

    private static final String BASE = "http://flashair/";
    private static final String COMMAND = BASE + "command.cgi";
    private static final String UPLOAD = BASE + "upload.cgi";
    private static final Handler handler = new Handler(Looper.getMainLooper());

    public static boolean upload(String uploadDir, File file, final Callback callback) {
        boolean result = false;
        int rt;
        if ((rt=checkConfig())!=1) {
            if(callback!=null){
                final int finalRt = rt;
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        if(finalRt == -1){
                            callback.onFailed("network not connect");
                        }else{
                            callback.onFailed("upload config not set");
                        }
                    }
                });
            }
            return result;
        }
        if ((rt=prepareUpload(uploadDir))!=1) {
            if(callback!=null){
                final int finalRt = rt;
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        if(finalRt == -1){
                            callback.onFailed("network not connect");
                        }else{
                            callback.onFailed("prepare upload failed");
                        }
                    }
                });
            }
            return result;
        }
        if(callback!=null){
            handler.post(new Runnable() {
                @Override
                public void run() {
                    callback.onStart();
                }
            });
        }
        final String uploadResult = postToFlashAir(file);
        if(uploadResult == null || !uploadResult.toUpperCase().contains("SUCCESS")){
            if(callback!=null){
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onFailed(uploadResult);
                    }
                });
            }
            return result;
        }else{
            result = true;
            if(callback!=null){
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.onSuccess();
                    }
                });
            }
        }
        return result;
    }

    private static int checkConfig() {
        String result = connectFlashAir(COMMAND + "?op=118");
        if (result == null) {
            return -1;
        }
        return result.equals("1")?1:0;
    }

    private static int prepareUpload(String dir){
        String result = connectFlashAir(UPLOAD + "?WRITEPROTECT=ON&UPDIR=/"+dir+"&FTIME="+getDateTime16());
        if (result == null) {
            return -1;
        }
        return result.equals("SUCCESS")?1:0;
    }

    private static String connectFlashAir(String uri) {
        String result = null;
        HttpURLConnection urlConnection = null;
        InputStream is = null;
        try {
            URL url = new URL(uri);
            urlConnection = (HttpURLConnection) url.openConnection();
            is = new BufferedInputStream(urlConnection.getInputStream());
            result = inputStreamToString(is);
        } catch (IOException exception) {
            exception.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            urlConnection.disconnect();
        }
        return result;
    }

    private static String postToFlashAir(File file) {
        String result = null;
        HttpURLConnection conn = null;
        BufferedInputStream bis = null;
        DataOutputStream bos = null;
        InputStream is = null;
        String BOUNDARY = UUID.randomUUID().toString();
        try {
            URL url = new URL(UPLOAD);
            conn = (HttpURLConnection) url.openConnection();
//            conn.setChunkedStreamingMode(1024 * 100);
            conn.setDoInput(true); // 允许输入流
            conn.setDoOutput(true); // 允许输出流
            conn.setUseCaches(false); // 不允许使用缓存
            conn.setRequestMethod("POST"); // 请求方式
            conn.setRequestProperty("Charset", "utf-8"); // 设置编码
//            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="
                    + BOUNDARY);
            bos = new DataOutputStream(conn.getOutputStream());
            bis = new BufferedInputStream(new FileInputStream(file));
            bos.writeBytes("--" + BOUNDARY + "\r\n");
            bos.writeBytes("Content-Disposition: form-data; name=\"upload.cgi\";filename=\"" + file.getName() +"\""+"\r\n");
            bos.writeBytes( "\r\n" );
            byte[] bytes = new byte[1024 * 8];
            int length;
            while ((length = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, length);
            }
            bos.writeBytes("\r\n");
            bos.writeBytes("--" + BOUNDARY + "--" + "\r\n");
            bos.flush();
            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                is = conn.getInputStream();
                result = inputStreamToString(is);
            }
        } catch (IOException exception) {
            exception.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            conn.disconnect();
        }
        return result;
    }

    private static String inputStreamToString(InputStream stream)
            throws IOException {
        Reader reader = new InputStreamReader(stream, "UTF-8");
        StringBuilder sb = new StringBuilder();
        char[] buffer = new char[1024];
        int num;
        while (0 < (num = reader.read(buffer))) {
            sb.append(buffer, 0, num);
        }
        return sb.toString();
    }

    public interface Callback{
        void onStart();
        void onSuccess();
        void onFailed(String msg);
    }

    public static String getDateTime16() {
        Calendar calendar = Calendar.getInstance();
        int year = (calendar.get(Calendar.YEAR) - 1980) << 9;
        int month = (calendar.get(Calendar.MONTH) + 1) << 5;
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int hours = calendar.get(Calendar.HOUR_OF_DAY) << 11;
        int minites = calendar.get(Calendar.MINUTE) << 5;
        int seconds = calendar.get(Calendar.SECOND) / 2;
        String rtnStr = "0x" + Integer.toHexString(year + month + day)
                + Integer.toHexString(hours + minites + seconds);

        return rtnStr;
    }

    public String getDate16(String date) {
        String rtnStr = "";
        try {
            int year = (Integer.parseInt(date.substring(0, 4)) - 1980) << 9;
            int month = (Integer.parseInt(date.substring(5, 7))) << 5;
            int day = Integer.parseInt(date.substring(8, 10));
            rtnStr = String.valueOf(year + month + day);
        } catch (Exception e) {
            System.err.println("ERROR: " + e.toString());
            e.printStackTrace();
        }
        return rtnStr;
    }


}
